#pragma once
#include "noncopyable.h"
#include "Timestamp.h"

#include <functional>
#include <memory>

class EventLoop;

/**
  理清楚 eventloop Channel Poller 之间的关系
  Channel 理解为通道，封装了 sockfd 和其感兴趣的 event，如 EPOLLIN、EPOLLOUT事件
  并提供了对其事件的操作
 */
class Channel : noncopyable {
public:
  using EventCallback = std::function<void()>;
  using ReadEventCallback = std::function<void(Timestamp)>;

  Channel(EventLoop *loop, int fd);
  ~Channel();
  // fd 得到 poller 通知以后，处理事件
  void handleEvent(Timestamp receiveTime);

  // 设置回调函数对象
  void setReadCallback(const ReadEventCallback &cb) { m_readCallback = std::move(cb); }
  void setWriteCallback(const EventCallback &cb) { m_writeCallback = std::move(cb); }
  void setCloseCallback(const EventCallback &cb) { m_closeCallback = std::move(cb); }
  void setErrorCallback(const EventCallback &cb) { m_errorCallback = std::move(cb); }

  // 防止当前 channel 被手动 renmove 掉，channel 还在执行回调
  void tie(const std::shared_ptr<void>&);
  int fd() const { return m_fd; }
  int events() const { return m_events; }
  void setRevents(int revt) { m_revents = revt; }
  bool isNoneEvent() { return m_events == kNoneEvent; }
  // 设置 fd 相应的事件状态
  void enableReading() { m_events |= kReadEvent; update(); }
  void disableReading() { m_events &= ~kReadEvent; update(); }
  void enableWriting() { m_events |= kWriteEvent; update(); }
  void disableWriting() { m_events &= ~kWriteEvent; update(); }
  void disableAll() { m_events = kNoneEvent; update(); }
  bool isNoneEvent() const { return m_events & kNoneEvent; }
  bool isWriting() const { return m_events & kWriteEvent; }
  bool isReading() const { return m_events & kReadEvent; }

  int index() const { return m_index; }
  void setIndex(const int index) { m_index = index; }
  EventLoop* ownerLoop() { return m_loop; }
  void remove();
private:
  void update();
  void handleEventWithGuard(Timestamp receiveTime);
private:
  static const int kNoneEvent;
  static const int kReadEvent;
  static const int kWriteEvent;

  EventLoop *m_loop; // 时间循环
  const int m_fd; // fd，Poller 监听的对象 epoll_ctl来设置
  int m_events; // 注册 fd 感兴趣的事件
  int m_revents; // poller返回具体发生的事件
  int m_index;
  
  std::weak_ptr<void> m_tie;
  bool m_tied;

  // 因为 channel 通道里面能够获得 fd 最终发生的具体的事件 revents
  ReadEventCallback m_readCallback;
  EventCallback m_writeCallback;
  EventCallback m_closeCallback;
  EventCallback m_errorCallback;
};